sorter = peripheral.wrap("front")

--print("Methods:")
--for k,v in pairs(peripheral.getMethods("bottom")) do
--	print("  * "..tostring(k)..": "..tostring(v))
--end

dir = {
	down=0,
	up=1,
	north=2,
	south=3,
	west=4,
	east=5
}

FURNACE_INPUT_SIDE = dir.up
FURNACE_FUEL_SIDE = dir.south
FURNACE_OUTPUT_SIDE = dir.south
STORAGE_SIDE = dir.north
INPUT_SIDE = dir.west
OUTPUT_SIDE = dir.down
SELF_SIDE = dir.east

function getUUID(id, meta)
  uuid = id + meta * 32768
  return uuid
end
 
function getID(uuid)
  id = uuid
  meta = 0
  if uuid > 32768 then
    meta = uuid%32768
    id = id - (meta * 32768)
  end
end

--print("Listing side south:")
--for uuid, count in pairs(sorter.list(dir.south)) do
--	print(" * "..tostring(uuid)..": "..tostring(count))
--end

--sorter.sort(dir.up, 1)

--sorter.extract(dir.south, 1, dir.north, 1)

items_ids = {
	cobblestone = 4,
	stone = 1,
	charcoal = 33031,
	iron_ore = 15,
	iron_ingot = 265,
	gold_ore = 14,
	gold_ingot = 266,
	sand = 12,
	glass = 20,
	glass_pane = 102,
	diamond = 264,
	computer = 1225,
	turtle = 1227,
	mining_turtle = getUUID(1127, 1),
	redstone = 331,
	wood_log = 17,
	chest = 54,
	stick = 280,
	diamond_pick = 278
}

function main()
	sorter.sort(dir.down)
	
	local requiredItem =  getNeededItem()
	
	if requiredItem == items_ids.stone or requiredItem == items_ids.glass or requiredItem == items_ids.iron_ingot then
		-- it's cooking
		os.startTimer(3)
	end
	
	print("Waiting for "..tostring(requiredItem))
	
	while true do
		event, param1, param2 = os.pullEvent()
		if event == 'isort_item' then
			print(tostring(param1).." == "..tostring(requiredItem))
			print(tostring(param1 == requiredItem))
			if param1 == requiredItem then
				print("Got the required item")
				requiredItem = onRequiredItemReceived(param1, param2)
				print("Waiting for "..tostring(requiredItem))
			else
				print("Non useful item received")
				sorter.sort(OUTPUT_SIDE)
			end
		elseif event == 'timer' then
			requiredItem = checkFurnaceWork()
		end
	end
end

function getNeededItem()
	if getStoredAmount(items_ids.mining_turtle, STORAGE_SIDE) < 1 then
		if getStoredAmount(items_ids.turtle, STORAGE_SIDE) < 1 then
			if getStoredAmount(items_ids.computer, STORAGE_SIDE) < 1 then
				if getStoredAmount(items_ids.stone, STORAGE_SIDE) < 7 then
					if getStoredAmount(items_ids.cobblestone, FURNACE_OUTPUT_SIDE) > 0 or getStoredAmount(items_ids.stone, FURNACE_OUTPUT_SIDE) > 0 then
						-- It's cooking stone
						return items_ids.stone
					else
						return items_ids.cobblestone
					end
				elseif getStoredAmount(items_ids.glass_pane, STORAGE_SIDE) < 1 then
					if getStoredAmount(items_ids.glass, STORAGE_SIDE) < 6 then
						if getStoredAmount(items_ids.sand, FURNACE_OUTPUT_SIDE) > 0 or getStoredAmount(items_ids.glass, FURNACE_OUTPUT_SIDE) > 0 then
							-- It's cooking glass
							return items_ids.glass
						else
							sorter.extract(STORAGE_SIDE, items_ids.sand, FURNACE_INPUT_SIDE, 8)
							sorter.extract(STORAGE_SIDE, items_ids.charcoal, FURNACE_FUEL_SIDE, 1)
							os.startTimer(3)
							return items_ids.glass
						end
					else
						CraftGlassPanes()
						return getNeededItem()
					end
				elseif getStoredAmount(items_ids.redstone, STORAGE_SIDE) < 1 then
					print("Waiting for redstone")
					return items_ids.redstone
				else
					CraftComputer()
					return getNeededItem()
				end
			elseif getStoredAmount(items_ids.iron_ingot, STORAGE_SIDE) < 7 then
				if getStoredAmount(items_ids.iron_ore, FURNACE_OUTPUT_SIDE) > 0 or getStoredAmount(items_ids.iron_ingot, FURNACE_OUTPUT_SIDE) > 0 then
					-- It's cooking iron
					return items_ids.iron_ingot
				else
					return items_ids.iron_ore
				end
			elseif getStoredAmount(items_ids.chest, STORAGE_SIDE) < 1 then
				CraftChest()
				return getNeededItem()
			else
				CraftTurtle()
				return getNeededItem()
			end
		elseif getStoredAmount(items_ids.diamond_pick, STORAGE_SIDE) < 2 then
			if getStoredAmount(items_ids.diamond, STORAGE_SIDE) < 3 then
				return items_ids.diamond
			elseif getStoredAmount(items_ids.stick, STORAGE_SIDE) < 2 then
				CraftSticks()
				return getNeededItem()
			else
				CraftDiamondPick()
				return getNeededItem()
			end
		else
			CraftMiningTurtle()
			return getNeededItem()
		end
	end
end

function onRequiredItemReceived(itemuuid, amount)
	if itemuuid == items_ids.cobblestone then
		if amount >= 8 then
			print("Got enough cobblestone, cooking it")
			sorter.sort(FURNACE_INPUT_SIDE, 8)
			sorter.sort(OUTPUT_SIDE)
			sorter.extract(STORAGE_SIDE, items_ids.cobblestone, OUTPUT_SIDE, getStoredAmount(items_ids.cobblestone, STORAGE_SIDE))
			sorter.extract(STORAGE_SIDE, items_ids.charcoal, FURNACE_FUEL_SIDE, 1)
			os.startTimer(3)
			return items_ids.stone
		else
			storedAmount = getStoredAmount(items_ids.cobblestone, STORAGE_SIDE)
			if (amount + storedAmount) >= 8 then
				print("Got enough cobblestone, cooking it")
				sorter.sort(FURNACE_INPUT_SIDE, amount)
				sorter.extract(STORAGE_SIDE, items_ids.cobblestone, FURNACE_INPUT_SIDE, 8 - amount)
				sorter.sort(OUTPUT_SIDE)
				sorter.extract(STORAGE_SIDE, items_ids.cobblestone, OUTPUT_SIDE, getStoredAmount(items_ids.cobblestone, STORAGE_SIDE))
				sorter.extract(STORAGE_SIDE, items_ids.charcoal, FURNACE_FUEL_SIDE, 1)
				os.startTimer(3)
				return items_ids.stone
			else
				print("Still not enough cobblestone")
				sorter.sort(STORAGE_SIDE)
				return items_ids.cobblestone
			end
		end
	elseif itemuuid == items_ids.redstone then
		sorter.sort(STORAGE_SIDE, 1)
		sorter.sort(OUTPUT_SIDE)
		return getNeededItem()
	elseif itemuuid == items_ids.iron_ore then
		if amount >= 8 then
			print("Got enough iron ore, cooking it")
			sorter.sort(FURNACE_INPUT_SIDE, 8)
			sorter.sort(OUTPUT_SIDE)
			sorter.extract(STORAGE_SIDE, items_ids.iron_ore, OUTPUT_SIDE, getStoredAmount(items_ids.iron_ore, STORAGE_SIDE))
			sorter.extract(STORAGE_SIDE, items_ids.charcoal, FURNACE_FUEL_SIDE, 1)
			os.startTimer(3)
			return items_ids.iron_ingot
		else
			storedAmount = getStoredAmount(items_ids.iron_ore, STORAGE_SIDE)
			if (amount + storedAmount) >= 8 then
				print("Got enough iron ore, cooking it")
				sorter.sort(FURNACE_INPUT_SIDE, amount)
				sorter.extract(STORAGE_SIDE, items_ids.iron_ore, FURNACE_INPUT_SIDE, 8 - amount)
				sorter.sort(OUTPUT_SIDE)
				sorter.extract(STORAGE_SIDE, items_ids.iron_ore, OUTPUT_SIDE, getStoredAmount(items_ids.iron_ore, STORAGE_SIDE))
				sorter.extract(STORAGE_SIDE, items_ids.charcoal, FURNACE_FUEL_SIDE, 1)
				os.startTimer(3)
				return items_ids.iron_ingot
			else
				print("Still not enough iron ore")
				sorter.sort(STORAGE_SIDE)
				return items_ids.iron_ore
			end
		end
	elseif itemuuid == items_ids.diamond then
		storedAmount = getStoredAmount(items_ids.diamond, STORAGE_SIDE)
		if 3 - storedAmount > amount then
			sorter.sort(STORAGE_SIDE, amount)
		else
			sorter.sort(STORAGE_SIDE, 3 - storedAmount)
			sorter.sort(OUTPUT_SIDE)
		end
		if amount + storedAmount < 3 then
			return items_ids.diamond
		end
		return getNeededItem()
	end
end

function getStoredAmount(itemuuid, side)
	storageList = sorter.list(side)
	if storageList[itemuuid] ~= nil then
		return storageList[itemuuid]
	else
		return 0
	end
end

function checkFurnaceWork()
	if getStoredAmount(items_ids.cobblestone, FURNACE_OUTPUT_SIDE) > 0 then
		-- waiting for stone to cook up
		print("Cooking not done")
		os.startTimer(3)
		return items_ids.stone
	elseif getStoredAmount(items_ids.stone, FURNACE_OUTPUT_SIDE) > 0 then
		-- stone finished cooking up
		print("Getting stone from furnace")
		sorter.extract(FURNACE_OUTPUT_SIDE, items_ids.stone, STORAGE_SIDE, 8)
		return getNeededItem()
	elseif getStoredAmount(items_ids.sand, FURNACE_OUTPUT_SIDE) > 0 then
		-- waiting for stone to cook up
		--print("Cooking not done")
		os.startTimer(3)
		return items_ids.glass
	elseif getStoredAmount(items_ids.glass, FURNACE_OUTPUT_SIDE) > 0 then
		-- glass finished cooking up
		print("Getting glass from furnace")
		sorter.extract(FURNACE_OUTPUT_SIDE, items_ids.glass, STORAGE_SIDE, 8)
		return getNeededItem()
	elseif getStoredAmount(items_ids.iron_ore, FURNACE_OUTPUT_SIDE) > 0 then
		-- waiting for iron to cook up
		--print("Cooking not done")
		os.startTimer(3)
		return items_ids.iron
	elseif getStoredAmount(items_ids.iron_ingot, FURNACE_OUTPUT_SIDE) > 0 then
		-- iron finished cooking up
		print("Getting iron from furnace")
		sorter.extract(FURNACE_OUTPUT_SIDE, items_ids.iron_ingot, STORAGE_SIDE, 8)
		return getNeededItem()
	else
		--print("Items have not gotten to the furnace yet")
		os.startTimer(3)
	end
end

function CraftGlassPanes()
	sorter.extract(STORAGE_SIDE, items_ids.glass, SELF_SIDE, 6)
	turtle.select(1)
	turtle.transferTo(2, 1)
	turtle.transferTo(3, 1)
	turtle.transferTo(5, 1)
	turtle.transferTo(6, 1)
	turtle.transferTo(7, 1)
	turtle.select(1)
	turtle.craft()
	sorter.extract(SELF_SIDE, items_ids.glass_pane, STORAGE_SIDE, 16)
end
		
function CraftComputer()
	sorter.extract(STORAGE_SIDE, items_ids.glass_pane, SELF_SIDE, 1)
	turtle.select(1)
	turtle.transferTo(10, 1)
	sorter.extract(STORAGE_SIDE, items_ids.redstone, SELF_SIDE, 1)
	turtle.select(1)
	turtle.transferTo(6, 1)
	sorter.extract(STORAGE_SIDE, items_ids.stone, SELF_SIDE, 7)
	turtle.select(1)
	turtle.transferTo(2, 1)
	turtle.transferTo(3, 1)
	turtle.transferTo(5, 1)
	turtle.transferTo(7, 1)
	turtle.transferTo(9, 1)
	turtle.transferTo(11, 1)
	turtle.select(1)
	turtle.craft()
	sorter.extract(SELF_SIDE, items_ids.computer, STORAGE_SIDE, 6)
end
		
function CraftChest()
	sorter.extract(STORAGE_SIDE, items_ids.wood_log, SELF_SIDE, 2)
	turtle.select(1)
	turtle.craft()
	turtle.transferTo(2, 1)
	turtle.transferTo(3, 1)
	turtle.transferTo(5, 1)
	turtle.transferTo(7, 1)
	turtle.transferTo(9, 1)
	turtle.transferTo(10, 1)
	turtle.transferTo(11, 1)
	turtle.craft()
	sorter.extract(SELF_SIDE, items_ids.chest, STORAGE_SIDE, 6)
end

function CraftTurtle()
	sorter.extract(STORAGE_SIDE, items_ids.chest, SELF_SIDE, 1)
	turtle.select(1)
	turtle.transferTo(10, 1)
	sorter.extract(STORAGE_SIDE, items_ids.computer, SELF_SIDE, 1)
	turtle.select(1)
	turtle.transferTo(6, 1)
	sorter.extract(STORAGE_SIDE, items_ids.iron_ingot, SELF_SIDE, 7)
	turtle.select(1)
	turtle.transferTo(2, 1)
	turtle.transferTo(3, 1)
	turtle.transferTo(5, 1)
	turtle.transferTo(7, 1)
	turtle.transferTo(9, 1)
	turtle.transferTo(11, 1)
	turtle.select(1)
	turtle.craft()
	sorter.extract(SELF_SIDE, items_ids.turtle, STORAGE_SIDE, 6)
end

function CraftSticks()
	sorter.extract(STORAGE_SIDE, items_ids.wood_log, SELF_SIDE, 1)
	turtle.select(1)
	turtle.craft()
	turtle.transferTo(5, 2)
	turtle.craft()
	sorter.extract(SELF_SIDE, items_ids.stick, STORAGE_SIDE, 8)
end

function CraftDiamondPick()
	sorter.extract(STORAGE_SIDE, items_ids.stick, SELF_SIDE, 2)
	turtle.select(1)
	turtle.transferTo(6, 1)
	turtle.transferTo(10, 1)
	sorter.extract(STORAGE_SIDE, items_ids.diamond, SELF_SIDE, 3)
	turtle.select(1)
	turtle.transferTo(2, 1)
	turtle.transferTo(3, 1)
	turtle.craft()
	sorter.extract(SELF_SIDE, items_ids.diamond_pick, STORAGE_SIDE, 1)
end

function CraftMiningTurtle()
	sorter.extract(STORAGE_SIDE, items_ids.turtle, SELF_SIDE, 1)
	turtle.select(1)
	turtle.transferTo(2, 1)
	sorter.extract(STORAGE_SIDE, items_ids.diamond_pick, SELF_SIDE, 3)
	turtle.select(1)
	turtle.craft()
	sorter.extract(SELF_SIDE, items_ids.mining_turtle, STORAGE_SIDE, 1)
end
	
arg = {...}
if (arg[1] == nil) then
	
	main()
elseif arg[1] == 'init' then
	print("initializing quarry master")
	print("Insert a piece of fuel into the interactive sorter")
	event, itemuuid, amount = os.pullEvent("isort_item")
	print(event.."setting the uuid "..tostring(itemuuid).." for the fuel")
	print("Insert a piece of iron ore into the interactive sorter")
	event, itemuuid, amount = os.pullEvent("isort_item")
	print(event.."setting the uuid "..tostring(itemuuid).." as iron ore")
	print("Insert a piece of cobblestone into the interactive sorter")
	event, itemuuid, amount = os.pullEvent("isort_item")
	print(event.."setting the uuid "..tostring(itemuuid).." as cobblestone")
else
	print("Listing side south:")
	for uuid, count in pairs(sorter.list(STORAGE_SIDE)) do
		print(" * "..tostring(uuid)..": "..tostring(count))
	end
	print("error: invalid parameter passed")
end
